{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 迁移学习\n",
    "使用 ```ImageNet``` 的一个数据量很小的子集, 练习迁移学习 <br>\n",
    "[参考](https://blog.csdn.net/weixin_43845931/article/details/89304733)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-03-18T02:01:00.926949Z",
     "start_time": "2020-03-18T02:01:00.922951Z"
    }
   },
   "outputs": [],
   "source": [
    "import os, gc\n",
    "from copy import deepcopy\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "from PIL import Image\n",
    "\n",
    "import torch\n",
    "from torch import nn, optim\n",
    "from torch.optim import lr_scheduler\n",
    "from torch.utils.data import DataLoader\n",
    "from torchvision.models import resnet18\n",
    "from torchvision import transforms, datasets\n",
    "\n",
    "from sklearn.model_selection import train_test_split\n",
    "from sklearn.metrics import classification_report"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-03-18T02:00:28.992814Z",
     "start_time": "2020-03-18T02:00:28.990403Z"
    }
   },
   "outputs": [],
   "source": [
    "BATCH_SIZE = 32\n",
    "\n",
    "WORKERS = 4"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 72,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-03-18T03:45:34.813058Z",
     "start_time": "2020-03-18T03:45:34.808533Z"
    }
   },
   "outputs": [],
   "source": [
    "# 预处理\n",
    "train_transform = transforms.Compose([\n",
    "        transforms.RandomResizedCrop(224),\n",
    "        transforms.RandomHorizontalFlip(0.5),\n",
    "        transforms.RandomVerticalFlip(0.5),\n",
    "        # 先转成 tensor 再标准化\n",
    "        transforms.ToTensor(),\n",
    "        transforms.Normalize( \n",
    "            mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225], inplace=True\n",
    "        )\n",
    "])\n",
    "\n",
    "val_transform = transforms.Compose([\n",
    "        transforms.Resize(256),\n",
    "        transforms.CenterCrop(224),\n",
    "        transforms.ToTensor(),\n",
    "        transforms.Normalize( \n",
    "            mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225], inplace=True\n",
    "        )\n",
    "])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 73,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-03-18T03:45:35.399356Z",
     "start_time": "2020-03-18T03:45:35.392822Z"
    }
   },
   "outputs": [],
   "source": [
    "data_dir = \"../data/hymenoptera_data/\"\n",
    "\n",
    "train = datasets.ImageFolder(data_dir + \"train/\", transform=train_transform)\n",
    "\n",
    "val = datasets.ImageFolder(data_dir + \"val/\", transform=val_transform)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 74,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-03-18T03:45:35.967251Z",
     "start_time": "2020-03-18T03:45:35.959994Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "244"
      ]
     },
     "execution_count": 74,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "len(train)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 75,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-03-18T03:45:36.418617Z",
     "start_time": "2020-03-18T03:45:36.413410Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "153"
      ]
     },
     "execution_count": 75,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "len(val)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 76,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-03-18T03:45:36.993482Z",
     "start_time": "2020-03-18T03:45:36.988528Z"
    }
   },
   "outputs": [],
   "source": [
    "train_loader = DataLoader(train, batch_size=BATCH_SIZE, shuffle=True, num_workers=WORKERS)\n",
    "\n",
    "val_loader = DataLoader(val, batch_size=BATCH_SIZE, shuffle=True, num_workers=WORKERS)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 训练模型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 77,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-03-18T03:45:38.641111Z",
     "start_time": "2020-03-18T03:45:38.625022Z"
    }
   },
   "outputs": [],
   "source": [
    "def train_model(model, criterion, optimizer, scheduler, num_epochs: int):\n",
    "    \"\"\"训练模型, 返回一个最优的模型, 未加入early_stopping\n",
    "    :param model, 模型\n",
    "    :param criterion: 损失函数\n",
    "    :optimizer: 优化器\n",
    "    :param scheduler: 学习率调整\n",
    "    :num_epochs: int, 总训练轮次\n",
    "    \"\"\"\n",
    "    train_acc_list = []\n",
    "    train_loss_list = []\n",
    "\n",
    "    val_acc_list = []\n",
    "    val_loss_list = []\n",
    "    \n",
    "    best_param = deepcopy(model.state_dict())\n",
    "    best_acc = 0.0\n",
    "    \n",
    "    for epoch in range(num_epochs):\n",
    "        model.train()\n",
    "        \n",
    "        # >>> training >>>\n",
    "        total_loss = 0.0\n",
    "        correct = 0\n",
    "        \n",
    "        for X, y in train_loader:\n",
    "            X, y = X.cuda(), y.cuda()\n",
    "            optimizer.zero_grad()\n",
    "            out = model(X)\n",
    "            # 预测的label\n",
    "            pred = out.max(1, keepdim=True)[1] # 找到概率最大的下标\n",
    "            loss = criterion(out, y)\n",
    "            loss.backward()\n",
    "            optimizer.step()\n",
    "            \n",
    "            total_loss += loss.item()\n",
    "            correct += pred.eq(y.view_as(pred)).sum().item()\n",
    "        # 统计结果\n",
    "        avg_train_loss = total_loss / len(train_loader)\n",
    "        train_acc = correct / len(train_loader.dataset)\n",
    "        \n",
    "        train_acc_list.append(train_acc)\n",
    "        train_loss_list.append(avg_train_loss)\n",
    "        \n",
    "        print(f\"{epoch+1}/{num_epochs} [train] loss: {avg_train_loss:.6f} acc: {train_acc}\")\n",
    "        # <<< training <<<\n",
    "        # >>> validation\n",
    "        model.eval()\n",
    "        total_loss = 0.0\n",
    "        correct = 0\n",
    "        \n",
    "        for X, y in val_loader:\n",
    "            X, y = X.cuda(), y.cuda()\n",
    "            out = model(X)\n",
    "            \n",
    "            loss = criterion(out, y)\n",
    "            \n",
    "            pred = out.max(1, keepdim=True)[1] # 找到概率最大的下标\n",
    "            total_loss += loss.item()\n",
    "            correct += pred.eq(y.view_as(pred)).sum().item()\n",
    "            \n",
    "        avg_val_loss = total_loss / len(val_loader)\n",
    "        val_acc = correct / len(val_loader.dataset)\n",
    "        \n",
    "        print(f\"{epoch+1}/{num_epochs}   [val] loss: {avg_val_loss:.6f} acc: {val_acc}\\n\")\n",
    "        \n",
    "        val_acc_list.append(val_acc)\n",
    "        val_loss_list.append(avg_val_loss)\n",
    "        \n",
    "        if val_acc > best_acc:\n",
    "            best_acc = val_acc\n",
    "            best_param = deepcopy(model.state_dict())\n",
    "        # 调整学习率\n",
    "        if scheduler:\n",
    "            scheduler.step()\n",
    "        \n",
    "    # 加载最优参数\n",
    "    model.load_state_dict(best_param)\n",
    "    \n",
    "    result = {\n",
    "        \"train_acc\": train_acc_list,\n",
    "        \"train_loss\": train_loss_list,\n",
    "        \"val_acc\": val_acc_list,\n",
    "        \"val_loss\": val_loss_list,\n",
    "        \"epochs\": num_epochs\n",
    "    }\n",
    "    \n",
    "    return model, result"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 84,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-03-18T03:56:58.233942Z",
     "start_time": "2020-03-18T03:56:58.222203Z"
    }
   },
   "outputs": [],
   "source": [
    "def draw_graph(result: dict, smooth: bool):\n",
    "    \"\"\" 画学习曲线\n",
    "    :param result: dict, train_model 函数的返回值\n",
    "    :param smooth: bool, 是否平滑\n",
    "    \"\"\"\n",
    "    def smooth_curve(points, factor=0.8):\n",
    "        \"\"\" 平滑\n",
    "        \"\"\"\n",
    "        smoothed_points = []\n",
    "        for point in points:\n",
    "            if smoothed_points:\n",
    "                previous = smoothed_points[-1]\n",
    "                smoothed_points.append(previous * factor + point * (1 - factor))\n",
    "            else:\n",
    "                smoothed_points.append(point)\n",
    "        return smoothed_points\n",
    "    \n",
    "    # 横坐标 epochs\n",
    "    epochs = range(1, result[\"epochs\"] + 1)\n",
    "    # 平滑\n",
    "    if smooth:\n",
    "        for name in [\"train_acc\", \"val_acc\", \"train_loss\", \"val_loss\"]:\n",
    "            result[name] = smooth_curve(result[name])\n",
    "            \n",
    "    plt.plot(epochs, result[\"train_acc\"], 'bo', label = 'Trianing acc')\n",
    "    plt.plot(epochs, result[\"val_acc\"], 'b', label = 'Validation acc')\n",
    "    plt.title('Training and validation acc')\n",
    "    plt.legend()\n",
    "\n",
    "    plt.figure()\n",
    "\n",
    "    plt.plot(epochs, result[\"train_loss\"], 'bo', label = 'Taining loss')\n",
    "    plt.plot(epochs, result[\"val_loss\"], 'b', label = 'Validation loss')\n",
    "    plt.title('Training and validation loss')\n",
    "    plt.legend()\n",
    "\n",
    "    plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 参数微调"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 86,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-03-18T03:57:49.527884Z",
     "start_time": "2020-03-18T03:57:49.280014Z"
    }
   },
   "outputs": [],
   "source": [
    "# 使用预训练 resnet 18\n",
    "model = resnet18(pretrained=True)\n",
    "\n",
    "# 修改最后的 fc 层\n",
    "fc_in_features = model.fc.in_features\n",
    "model.fc = nn.Linear(fc_in_features, 2)\n",
    "\n",
    "model = model.cuda()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 87,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-03-18T03:57:52.734727Z",
     "start_time": "2020-03-18T03:57:52.731850Z"
    }
   },
   "outputs": [],
   "source": [
    "# loss 函数\n",
    "criterion = nn.CrossEntropyLoss().cuda()\n",
    "# 优化器\n",
    "optimizer = optim.Adam(model.parameters(), lr=1e-5, weight_decay=1e-5)\n",
    "# optimiezer = optim.SGD(model.parameters(), lr=0.001, momentum=0.9)\n",
    "# 学习率衰减\n",
    "# model_lr_scheduler = lr_scheduler.StepLR(optimiezer, step_size=7, gamma=0.1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 88,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-03-18T03:59:56.924977Z",
     "start_time": "2020-03-18T03:57:54.372819Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1/35 [train] loss: 0.735926 acc: 0.5450819672131147\n",
      "1/35   [val] loss: 0.685572 acc: 0.5686274509803921\n",
      "\n",
      "2/35 [train] loss: 0.618559 acc: 0.6229508196721312\n",
      "2/35   [val] loss: 0.550562 acc: 0.6993464052287581\n",
      "\n",
      "3/35 [train] loss: 0.545222 acc: 0.7131147540983607\n",
      "3/35   [val] loss: 0.465351 acc: 0.7973856209150327\n",
      "\n",
      "4/35 [train] loss: 0.483860 acc: 0.7540983606557377\n",
      "4/35   [val] loss: 0.408957 acc: 0.8496732026143791\n",
      "\n",
      "5/35 [train] loss: 0.422374 acc: 0.8073770491803278\n",
      "5/35   [val] loss: 0.363055 acc: 0.8823529411764706\n",
      "\n",
      "6/35 [train] loss: 0.355829 acc: 0.8770491803278688\n",
      "6/35   [val] loss: 0.334687 acc: 0.8888888888888888\n",
      "\n",
      "7/35 [train] loss: 0.330303 acc: 0.8770491803278688\n",
      "7/35   [val] loss: 0.300503 acc: 0.9019607843137255\n",
      "\n",
      "8/35 [train] loss: 0.276473 acc: 0.9016393442622951\n",
      "8/35   [val] loss: 0.291913 acc: 0.8954248366013072\n",
      "\n",
      "9/35 [train] loss: 0.258466 acc: 0.9139344262295082\n",
      "9/35   [val] loss: 0.265858 acc: 0.9019607843137255\n",
      "\n",
      "10/35 [train] loss: 0.244291 acc: 0.930327868852459\n",
      "10/35   [val] loss: 0.258166 acc: 0.8954248366013072\n",
      "\n",
      "11/35 [train] loss: 0.228626 acc: 0.9344262295081968\n",
      "11/35   [val] loss: 0.253728 acc: 0.9019607843137255\n",
      "\n",
      "12/35 [train] loss: 0.209538 acc: 0.9426229508196722\n",
      "12/35   [val] loss: 0.249224 acc: 0.9019607843137255\n",
      "\n",
      "13/35 [train] loss: 0.199712 acc: 0.9344262295081968\n",
      "13/35   [val] loss: 0.240121 acc: 0.9084967320261438\n",
      "\n",
      "14/35 [train] loss: 0.221008 acc: 0.9262295081967213\n",
      "14/35   [val] loss: 0.222851 acc: 0.9084967320261438\n",
      "\n",
      "15/35 [train] loss: 0.207655 acc: 0.9385245901639344\n",
      "15/35   [val] loss: 0.222139 acc: 0.9084967320261438\n",
      "\n",
      "16/35 [train] loss: 0.206759 acc: 0.930327868852459\n",
      "16/35   [val] loss: 0.214963 acc: 0.9150326797385621\n",
      "\n",
      "17/35 [train] loss: 0.184976 acc: 0.9262295081967213\n",
      "17/35   [val] loss: 0.208093 acc: 0.9281045751633987\n",
      "\n",
      "18/35 [train] loss: 0.192305 acc: 0.9344262295081968\n",
      "18/35   [val] loss: 0.206048 acc: 0.9281045751633987\n",
      "\n",
      "19/35 [train] loss: 0.180975 acc: 0.9385245901639344\n",
      "19/35   [val] loss: 0.209511 acc: 0.9281045751633987\n",
      "\n",
      "20/35 [train] loss: 0.147660 acc: 0.9508196721311475\n",
      "20/35   [val] loss: 0.218827 acc: 0.9281045751633987\n",
      "\n",
      "21/35 [train] loss: 0.151396 acc: 0.9549180327868853\n",
      "21/35   [val] loss: 0.211762 acc: 0.934640522875817\n",
      "\n",
      "22/35 [train] loss: 0.149025 acc: 0.9590163934426229\n",
      "22/35   [val] loss: 0.201854 acc: 0.934640522875817\n",
      "\n",
      "23/35 [train] loss: 0.154058 acc: 0.9262295081967213\n",
      "23/35   [val] loss: 0.202265 acc: 0.934640522875817\n",
      "\n",
      "24/35 [train] loss: 0.150440 acc: 0.9426229508196722\n",
      "24/35   [val] loss: 0.210267 acc: 0.9215686274509803\n",
      "\n",
      "25/35 [train] loss: 0.130694 acc: 0.9713114754098361\n",
      "25/35   [val] loss: 0.201489 acc: 0.9281045751633987\n",
      "\n",
      "26/35 [train] loss: 0.123759 acc: 0.9590163934426229\n",
      "26/35   [val] loss: 0.199830 acc: 0.9281045751633987\n",
      "\n",
      "27/35 [train] loss: 0.126719 acc: 0.9549180327868853\n",
      "27/35   [val] loss: 0.206049 acc: 0.934640522875817\n",
      "\n",
      "28/35 [train] loss: 0.107742 acc: 0.9754098360655737\n",
      "28/35   [val] loss: 0.204489 acc: 0.9281045751633987\n",
      "\n",
      "29/35 [train] loss: 0.080428 acc: 0.9836065573770492\n",
      "29/35   [val] loss: 0.203418 acc: 0.934640522875817\n",
      "\n",
      "30/35 [train] loss: 0.113404 acc: 0.9631147540983607\n",
      "30/35   [val] loss: 0.202585 acc: 0.934640522875817\n",
      "\n",
      "31/35 [train] loss: 0.088709 acc: 0.9836065573770492\n",
      "31/35   [val] loss: 0.204033 acc: 0.9281045751633987\n",
      "\n",
      "32/35 [train] loss: 0.108985 acc: 0.9672131147540983\n",
      "32/35   [val] loss: 0.194906 acc: 0.9281045751633987\n",
      "\n",
      "33/35 [train] loss: 0.123203 acc: 0.9508196721311475\n",
      "33/35   [val] loss: 0.191199 acc: 0.9281045751633987\n",
      "\n",
      "34/35 [train] loss: 0.090832 acc: 0.9713114754098361\n",
      "34/35   [val] loss: 0.198409 acc: 0.9281045751633987\n",
      "\n",
      "35/35 [train] loss: 0.115490 acc: 0.9631147540983607\n",
      "35/35   [val] loss: 0.197358 acc: 0.934640522875817\n",
      "\n"
     ]
    }
   ],
   "source": [
    "model, result = train_model(\n",
    "    model=model,\n",
    "    criterion=criterion,\n",
    "    optimizer=optimizer,\n",
    "#     scheduler=model_lr_scheduler,\n",
    "    scheduler=None,\n",
    "    num_epochs=35\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 89,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-03-18T04:00:20.353154Z",
     "start_time": "2020-03-18T04:00:20.077599Z"
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "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9OvXj1//+tc88MADLFmyhFNOOYX8/HymT59O+/btKSoqIj8/nzFjxvDoo48CMGTIEK677joWLVpEz5496d69O2+//TYFBQU888wz5YtvlXn22WcZNWoUW7ZsoXXr1kyaNIl9992XdevWMWzYMIqKijAzbr/9di688EJefPFFbr75ZrZt20Z+fj6vvvpqzR/8HBFlTHeqxmtHSda1Ne572zb49ltYsiTc1qwJiXbbtsT3a9fC8uUhcS9fvv3xypUhqSfSqBG0aLH9Vr8+rFsHW7eGfcffl90qfn7ZLdnnpEJeXoixefPt8R5ySHheEyzU2GtfYWGhVyxBfPzxxxxxxBEAXHcdVLL8927p0gViy5AndO655zJ06FD69OnD6NGjWbFiBffeey8lJSVs2LCBvfbai+XLl3PCCSfw2WefYWY0bdqUdevW7ZDQx4wZw9y5c3n00Uf56KOP6Nq1K++++y6FhYWsXLmSVq1asW3bNk477TQeeOABOnXqtEMCB8qff/nllwwaNIh3330Xd+f4449n4sSJtGzZku9973sUFRXRpUsXLrroInr37s3FF1+8w8+0atUqWrRogZkxYcIEPv74Y+6//35uvPFGNm/eXL42+6pVqygpKaFr167MmDGDDh06lMdaUfzvSrZr377yZN2uXShlwM5JH0Ii3pW6dVXfBqpjy5aQGNevT35buXJ74l6yBBYvhv/8p/rJMS8PWreGvfeG/Pzt9/GPW7WCli13TOCxtexSwn3HZF/ZrbR058elpYkfN226PYE3aRJ67alkZrPcvbCy19RDr6Cs7NKnTx8mT55c3it2d26++WZmzJhBvXr1WLx4Md988w377bdfpfuZMWMG11xzDQCdOnWiU6dO5a9NmTKF8ePHU1JSwtKlS5k/f/4Or1f05ptvcsEFF5Sv+Ni3b1/eeOMNevfuTYcOHejSpQuQeIne4uJifvzjH7N06VK2bNlChw4dgLBS5OTJk8vbtWzZkmeffZaTTz65vI2W2N1RKsopu9trXrUKPv0UPvss3J9wQvhDssceMHEiPPlk6LU2aLC95FC/fkg2a9eG23ff7Xy/eXP049CqFRxwABQUQMeO4XHZ8wMOCMmsYnmjrGRR9rhhw1CqSCez7XHmgoz9MarqSdeU888/n+uvv54PPviAjRs30rVrVyAsdrVs2TJmzZpF/fr1ad++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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "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GTJkCAUFBVx44YVs3759b7urr76awsJCOnfuzF13hRnUDz74IGvWrKFv37707RuugczPz2f9+vUAjBs3bm+p3PHjx+99vY4dO3L55ZfTuXNnvvvd7+73OoksXLiQk046iYKCAs4777y9VSMffPDBveV1S4qE/eMf/9i7wEf37t3LLUcQRU5e+n/LLWF++bXXwsCB8NxzZetOJKOVj0RCxyi21kTadOsGsVyYUIsWLejZsycvvvgigwYNYtq0aVx44YWYGQ0aNGDGjBkccsghrF+/npNOOomBAwcmXVfz4YcfplGjRixevJjFixfTo0ePvY+NGTOG5s2bs3v3bk4//XQWL17MDTfcwLhx45g9ezZ5eXn7HWvBggVMnjyZN998E3fnxBNPpE+fPhx22GG8//77PPnkkzzyyCNccMEFPPvss1x88cVJf8cf/vCHPPTQQ/Tp04c777yTu+++m/Hjx3PvvfeycuVK6tevv3eY5/7772fChAn06tWLrVu30qBBgwq824nlXA+9xDXXwGOPwf/+L/TrB5s3R3teVVaRE5H9xQ+7xA+3uDu33347BQUFnHHGGXz88cesXbs26XHmzJmzN7EWFBRQUFCw97Hp06fTo0cPunfvTlFREUuWJLsGMpg7dy7nnXcejRs3pkmTJpx//vm89tprAHTo0IFu3boBqUv2QigytnHjRvr06QPAJZdcwpw5c/bGOGzYMKZMmUKdOqEf3atXL26++WYefPBBNm7cuHf/wcjJHnqJSy6Bhg3DePqZZ4bx9ebNUz9HV5OKpO5JV6Zzzz13b5XC7du37+1ZT506lXXr1rFgwQLq1q1Lfn5+whK68RL13leuXMn999/PvHnzOOywwxg+fHi5x0k1j6N0yd7yhlyS+ctf/sKcOXOYOXMmv/jFLygqKmLkyJEMGDCAWbNmcdJJJ/Hyyy9z3HHHHdDxS+RsD73EBRfAn/4Uvj6edhp89lnq9rqaVCRzmjRpwqmnnsqll16638nQTZs28Y1vfIO6desye/ZsVicqyhSnd+/eTI3NZHj33XdZvHgxAJs3b6Zx48YceuihrF27lr/+9a97n9O0adOE49S9e/fmueeeY9u2bXz55ZfMmDGDU045pcK/26GHHsphhx22t3f/xz/+kT59+rBnzx4++ugj+vbty9ixY9m4cSNbt27lgw8+4Pjjj+e2226jsLCQf//73xV+zdJyuode4pxz4IUXYNAg6NMHXn4ZWicsThDoalKRzBk6dCjnn3/+fjNehg0bxjnnnENhYSHdunUrt6d69dVX86Mf/YiCggK6detGz549AejatSvdu3enc+fOHHXUUfTq1Wvvc6644gr69+9Pq1atmD179t79PXr0YPjw4XuPMWLECLp3755yeCWZxx9/nKuuuopt27Zx1FFHMXnyZHbv3s3FF1/Mpk2bcHduuukmmjVrxs9//nNmz55N7dq16dSpE/3796/w65UWqXxuZaiM8rmvvQYDBkDLlmFsPT8/rYcXyWk1uXxurqpo+dycH3KJd8opIZF/8UXoqcdmJImI1AjVKqEDfPvb8Le/waefwqWXJl7wQkSkOqp2CR2gsDBcfPTnP8NDD2U6GpHskakhVqm4A/lbVcuEDnD99XD22XDrrVAD6tqLlKtBgwZs2LBBST0HuDsbNmyo8MVG1WKWSyJmMHkydO0KQ4bAggUQq/ETydSpVbNArkhVadOmDcXFxaxbty7ToUgEDRo0oE2bNhV6TrVN6AB5eTBlCpx+OtxwA/z+99GeV1LAq+Tio5ICXqCkLrmrbt26dOjQIdNhSCWqtkMuJfr2DT3tyZPhyaRLb+xPBbxEJBdV+4QOcNdd0KsXXHklfPBB+e1VwEtEclGNSOh16oRhlNq1YehQ2LkzdXsV8BKRXFQjEjqEmi2/+x3Mmwd33JG67ZgxZcvxqoCXiGS7GpPQAc4/H666KsxRL7US1n5UwEtEclG1quUSxfbt4WrSdetg0SI44ogqD0FE5IDVmFouUTRsGJav27w51FPXNRYiUl3UuIQO0LlzWGj6b3+DiRMzHY2ISHrUyIQOYSz9jDNCaYADKHssIpJ1amxCN4NHHw0/L7sM9uzJdEQiIgcnUkI3s35mtszMlpvZyCRtLjCzJWZWZGZPpDfMytG+Pfz3f8Mrr2joRURyX7kJ3cxqAxOA/kAnYKiZdSrV5hjgZ0Avd+8M3FgJsVaKESPgu98NQy8rV1bsuVOnhlWRatUKP2NLHIqIZESUHnpPYLm7r3D3ncA0YFCpNpcDE9z9CwB3L2ep5uxhBo88EpLypZdGH3opKeC1enWYKVNSwEtJXUQyJUpCbw18FLddHNsX71jgWDN73czeMLN+iQ5kZleY2Xwzm59NJTzbtQuzXl59FR5+ONpzVMBLRLJNlIRuCfaVnr1dBzgGOBUYCjxqZs3KPMl9krsXunthy5YtKxprpbrsMvje9+CnP4UVK8pvrwJeIpJtoiT0YqBt3HYbYE2CNs+7+9fuvhJYRkjwOaNk6KVOnWhDLyrgJSLZJkpCnwccY2YdzKweMASYWarNc0BfADPLIwzBROjnZpe2beGBB+Af/4AJE1K3VQEvEck25SZ0d98FXAe8BCwFprt7kZndY2YDY81eAjaY2RJgNnCru2+orKAr049+BP37w8iRqWunq4CXiGSbGlecK4riYujSJaxHOnt2mAEjIpINVJyrgtq0gfHjYc4c+M1vMh2NiEg0SuhJXHIJDBhQ/tCLiEi2UEJPwgx++1uoWzdcTapaLyKS7ZTQU2jTZt8FR5MmZToaEZHUlNDLceml+8rs6qIhEclmSujlKLngyB0uv1wrHIlI9lJCjyA/H+67L6xw9NhjmY5GRCQxJfSIrr4aeveGm26CNaULH4iIZAEl9Ihq1YLf/Q527gzL10UdelHNdBGpKkroFXD00fDLX8Kf/wzTppXfXjXTRaQq6dL/Ctq9G04+Gd5/H4qK4PDDk7fNzw9JvLT27bUwtYgcGF36n0a1a8Pvfw9btsD116duq5rpIlKVlNAPQMeOMHo0PP00PPts8naqmS4iVUkJ/QDdcgv06AHXXgsbkhQKVs10EalKSugHqG7dMPSyYQP8+MeJ26hmuohUJSX0g9C1K9xxR5i1Mn164jbDhoUToHv2hJ9K5iJSWZTQD9KoUXDiiXDllWFhDBGRTFFCP0h16sCUKfD116GGusrsikimKKGnwdFHw69/Da+8EsrtiohkghJ6mlx6KZx3Htx+OyxalOloRKQmUkJPE7MwgyUvDy66CLZvz3REIlLTKKGnUV4eTJ4MS5aEtUhFRKqSEnqafe97cMMN8OCD8NJL0Z6jiowikg6RErqZ9TOzZWa23MzK9D3NbLiZrTOzhbHbiPSHmjvuvRc6d4bhw2HdutRtVZFRRNKl3IRuZrWBCUB/oBMw1Mw6JWj6lLt3i90eTXOcOaVhw5CQP/88JOdUBS1HjYJt2/bft21b2C8iUhFReug9geXuvsLddwLTgEGVG1bu69oVfvUreO65sDBGMqrIKCLpEiWhtwY+itsuju0r7ftmttjMnjGztokOZGZXmNl8M5u/rryxiGrgppvgtNNCrZf330/cRhUZRSRdoiR0S7Cv9CDCn4F8dy8AXgYeT3Qgd5/k7oXuXtiyZcuKRZqDatWCxx+HevVCDZedO8u2UUVGEUmXKAm9GIjvcbcB9lsm2d03uPtXsc1HgBPSE17ua9MGHnkE5s2DO+8s+7gqMopIukRJ6POAY8ysg5nVA4YAM+MbmFmruM2BwNL0hZj7Bg+Gyy+H++6Dv/+97OOqyCgi6VBuQnf3XcB1wEuERD3d3YvM7B4zGxhrdoOZFZnZIuAGYHhlBZyrxo8PKx398IflT2UUETkQWiS6Ci1aFErtnn46vPBCGGIREakILRKdJbp2hfvvh1mzwpWkIiLppIRexa69Fs45B376U3jnnUxHIyLViRJ6FTMLa5Hm5cGQIbB1a6YjEpHqQgk9A/Ly4I9/DBcbJVtgWkSkopTQM+S00+BnPwu99WnTym+viowiUh4l9AwaPRpOOiksML1yZfJ2qsgoIlEooWdQ3brwxBPh/kUXhYWmE1FFRhGJQgk9wzp0CJf6v/EG/PzniduoIqOIRKGEngUuvHBfaYA//KHs46rIKCJRKKFnid/8JpwoHTECXn11/8dUkVFEolBCzxL16sGzz8LRR8N558G//73vMVVkFJEoVMsly6xcGWa+NG4Mb74JNaBsvIhUgGq55JAOHWDmTPjkExg0CLZvz3REIpIrlNCz0IknwpQpYebLJZeEOukiIuVRQs9S3/8+jB0LTz+t+eYiEk2dTAcgyf3kJ7B8Odx7L3zzm2EGjIhIMkroWcwsTGdctQquuirMbjnzzExHJSLZSkMuWa5OHZg+HTp1CmuTvvtu8rYq4CVSsymh54BDDoG//CVMZTzrLCguLttGBbxERAk9R7RtG5au27gR+vcPP+OpgJeIKKHnkG7dYMYMWLYszFHfsWPfYyrgJSJK6Dnm9NNDAa85c+Dii2H37rBfBbxERAk9Bw0ZAg88EGq//PjHYcxcBbxEJFJCN7N+ZrbMzJab2cgU7QabmZtZwjoDkj433gi33AITJoR56irgJSLlzkM3s9rABOBMoBiYZ2Yz3X1JqXZNgRuANysjUCnrvvtCzZfbb4dWrWD4cCVwkZosSg+9J7Dc3Ve4+05gGjAoQbtfAGOBHQkek0pQq1ZYZPrMM8NVpLNmZToiEcmkKAm9NfBR3HZxbN9eZtYdaOvuL6Q6kJldYWbzzWz+unXrKhyslFVSR71rV/jBD+CttzIdkYhkSpSEbgn27S2ibma1gAeAn5R3IHef5O6F7l7YUoW+06Zp09A7P+IIGDAA3nsv0xGJSCZESejFQNu47TbAmrjtpkAX4FUzWwWcBMzUidGqdfjh8OKL4YRo376wdGnidioPIFJ9RUno84BjzKyDmdUDhgAzSx50903unufu+e6eD7wBDHR3LUdUxY45Bl55JcxN790b3n57/8dVHkCkeis3obv7LuA64CVgKTDd3YvM7B4zG1jZAUrFdOkCr70W5qD37Quvv77vMZUHEKnetKZoNfXRR3DGGaGQ13PPhZkwtWqFnnlpZloVSSRXaE3RGqht21Ae4Oij4eyzQ1JXeQCR6k0JvRo7/HCYPRu6dw+11M86S+UBRKozJfRqrnlz+Pvfw0nS3/4WLrxQ5QFEqisl9BqgadOwQMZZZ8HkyXDttWHMfNUqJXOR6kQJvYZo2BD+9Ce44AL46U/h1lth165MRyUi6aRFomuQevXgiScgLw/uvx8WLoQnnwzbIpL71EOvYWrXDiV3f/e7MF/9hBNgwYL92+hqUpHcpIReQ116KcydG+736hXG1kFXk4rkMiX0GqywEObPh5NPDgn+6qtDbXVdTSqSmzSGXsO1bBmKeo0aBWPHJm+nxaZFsp966EKdOmH1o6efDvPTE9HVpCLZTwld9ho8OKxPWjqp62pSkdyghC77+elPYeLEfSUC6tWDO+/UBUgiuUAJXcq4/HL48kuYPh0OOSQk9DFj4OuvMx2ZiKSihC5J/eAHsGQJnHsu3HEHnHQSLF6c6ahEJBkldEmpZUt46il45plQW72wEO65Bx5/XBcfiWQbTVuUSL7/fejTB378Y7jrrnDitGSxjJKLj0Bj7SKZpB66RJaXF3riLVuWXflIFx+JZJ4SulTY+vWJ969eXbVxiMj+lNClwpJdZFS/PhQVVW0sIrKPErpU2JgxZZeyq1s3XHHatSvcfDNs3pyZ2ERqMiV0qbBhw8LSdfFL2U2eHFZAuuwyGD8ejj0W/vjHsmPtIlJ5IiV0M+tnZsvMbLmZjUzw+FVm9i8zW2hmc82sU/pDlWwybFhI4PFL2eXlhatM33orTGX84Q/hlFPCQhoiUvnKTehmVhuYAPQHOgFDEyTsJ9z9eHfvBowFxqU9UskZhYXwf/8Xrjj95z+he/dwxemkSZmOTKR6i9JD7wksd/cV7r4TmAYMim/g7vEjpo0BfdGu4Z58Mkxx3LMnbG/ZAldeGearl+wTkfSKktBbAx/FbRfH9u3HzK41sw8IPfQb0hOe5KpRo8oulAHwyCNhhaS33676mESquygJPVGF7DI9cHef4O7fBG4D7kh4ILMrzGy+mc1ft25dxSKVnJJqQYwVK8KwzDXXwOefV11MItVdlIReDLSN224DrEnRfhpwbqIH3H2Suxe6e2HLli2jRyk5J9lc9fbtYdkyuP76cAL1W9+CRx/VMIxIOkRJ6POAY8ysg5nVA4YAM+MbmNkxcbu+2g8AAA3hSURBVJsDgPfTF6LkokRz1UsWymjWDH796zDs0rx5OHlau3aYJfOHP2QmXpHqoNyE7u67gOuAl4ClwHR3LzKze8xsYKzZdWZWZGYLgZuBSyotYskJieaqT5q0f/Gud9+Fj+LOzmzYAMOHw4gR8NVXVR6ySM4zz9CVH4WFhT5//vyMvLZkh/z85PVf2rQJqyeNGAENG1ZpWCJZzcwWuHthosd0pahkTKoTpx06wA03hKQ/dmyY9igiqSmhS8akOnE6Zw784x/QrRvcdlvYN2oUfPxx1cYokkuU0CVjUp04BejdG156Ce6+G3bsgF/9KgzF9OoF8+ZVfbwi2U4JXTImyonTqVPhvvtg+/Z9+/7v/6Bnz5DYn34adu2q+thFspFOikpWS3bi9LDDwm3FijB0c/31odLjYYdVeYgiVUonRSVnJTtxunEjvPcePP88fPObcOut0KJF6Om3agVTplRtnCLZQAldslqyE6ft2oWLkQYODD3zBg321V7/9NNQuvdHP4JNm6ouVpFMU0KXrFbeiVMIs1927Ni/jTs89hgceWSYy/7WW1psQ6o/JXTJalFOnKaaz37RRTBtGpx4YqjLPmECqC6cVFc6KSo5L9mJ0/btw2pKmzeH+uwTJ8I774Shmr594YIL4LzzQg0ZkVyhk6JSrZU3LHPIIWFxjZtvDidMd++GV18Ni20ccQSceWao075+fZWHLpJWSuiS86LOZ7/ySvjkk7C9a1c4kTpgQOjFxyf3iRPhgw805i65R0MuUiOkGpZZuRIWLQoXKU2fDsuXh8eOPDJcrdq7N/TpAx07hg8MkUxKNeRSp6qDEcmEZCdOP/wwJOlu3aCoCHbuDPubN99XU2batLAvLw9OOSUk+F694JhjQm13kWyhhC41Qrt2iXvoJfPcp04Nwy4l66B+/nnotU+cCN/5TkjsJbcZM/Y9v1mz0Pvv0GHfLX679Ni+SGXSkIvUCKUTNoRkWzLWXt5MmXjFxWFe+8qV+99Wrdq/5gyEYmLf+lbZW7t2UEtnsOQAaMhFarySE6SjRoVhlnbtwiyYkv2phmTiTZ1a9hi/+U14zB0++2xfgl+xIqyfumxZeF78VasNGoQhm+OOC8M9PXqEefKHH57e31tqFvXQRYjWQy+vl59KSbIvSfAltyVLQuIv0apVSOzxtw4ddDJW9knVQ1dCFyFasq7IsExFbNoECxeGi55KbkuWhPnyEObRH3tsGKqJ/3nssdC48YG/ruQmJXSRCBINp8T3vGvVSjw33Qz27ElvLNu3h0W033kH/vWvfT360kNArVuHBN+hQ5iZ06xZKCEc/7PkfvPmULdueuOUqqeELpIGldVDr4jt2+H990Nyf++9fT9Xr4YvvoCvvkr+XLMwRt+2bfJbq1ahNIJkL50UFUmDMWMSD8vEV36E8nv6B6NhQygoCLdEduwIteI3bgwJPv7+unXw0UfhtnQp/O1vsHXr/s+vVStcMXvkkeHWuvW++yXbeXkhjkaNQo9f4/vZQwldJKLyZspA2bH41avDdvzzK1ODBiEhH3FE+W3dw/j9hx/uS/TFxaE8wpo1YabO66/Dhg3Jj1G79r7k3qjR/vcbNQpj/I0b77ufbF/px+P3aZgoukhDLmbWD/g1UBt41N3vLfX4zcAIYBewDrjU3RN8Od1HQy5SHWXDsEy67dgRFg1Zsybc1q8PQz/btu37Wfr+tm3w5ZeJf1Z0lLd27f0/JEp/eNSvH5J+vXrhZ8ktfvvQQ6Fly3DLy9t3/5BDcu8bxkENuZhZbWACcCZQDMwzs5nuviSu2TtAobtvM7OrgbHAhQcfukhuiTqfPZc0aBA+qPLzD/5Y7uEDonSST/YBUPpDovQHx/r1oVzD11/v+1lyi99fMmOotHr1QoLPywvnF0puRxxR9n5eXvafX4gy5NITWO7uKwDMbBowCNib0N19dlz7N4CL0xmkSK4or8RAicocZ89mZqFn3bBh1b7ul1+Gcwjr1oUPgUT3164NJ5w//bTsClgQzi80aLCv51+v3v734/fVr1/2fvy+H/wA/t//S//vGSWhtwY+itsuBk5M0f4y4K+JHjCzK4ArANolWyxSJIdFOXGa6XH2mqhk3D7Ktwx32LIlJPhPPw0/S+5v3172G8HOnWXvb9sWTkZ/9dW+fTt37ts+/vjMJfREI0wJR8HM7GKgEOiT6HF3nwRMgjCGHjFGkZwR5cTpqFH7J3wI26NGKaFnA7Mwtn7IIaE8Qy6JUh6oGGgbt90GWFO6kZmdAYwCBrp7itmwItXbsGHhBOiePeFn6SRdkbox+fnhq35+ftgWSSVKQp8HHGNmHcysHjAEmBnfwMy6AxMJyfyz9IcpUn0kG22M318yLLN6dRgCKBmWUVKXVMpN6O6+C7gOeAlYCkx39yIzu8fMBsaa/RfQBHjazBaa2cwkhxOp8cpbAxVSD8vEUy9e9uPuGbmdcMIJLlJTTZni3r69u1n4OWXK/o+buYe++f43s/2P0ajR/o83alT2WOW9luQWYL4nyauq5SKShaJcoFTZJX8lO6W6sEhrpohkoSjDMlFOrkYdupHqQQldJAsNGxZ60e3bh2l07duX7VVHObmqGTU1ixK6SJYqb/pjlF68ZtTULEroIjkqSi8+nTNqJPspoYvksPJ68VGSvoZlqg/VQxep5oYNSz2jJUpBMdWfyQ3qoYvUcLrQqfpQQhep4dI1LKOTq5mnC4tEpFzputBJDp4uLBKRg5KuC51AwzKVSQldRMqVrgudNCxTuTTkIiJpEaVujIZlDp6GXESk0mnOe+ZpHrqIpI3mvGeWeugiUmU0571yKaGLSJXRnPfKpYQuIlWqvPozUWbLVHUvPle+DSihi0hWSdec96i9+PKSdU59G0i2Nl1l37SmqIgkU946qO3bJ15ztX37irWJsi5rlONEiTlqm/KQYk1RJXQRyTlREnGUhbajJOt0LdgddVHv8qRK6BpyEZGcU5VL9KVrTL8qFhJRQheRnFRVS/Sla0w/6kVVByNSQjezfma2zMyWm9nIBI/3NrO3zWyXmQ1OX3giIgcmXUv0pevbQJQ2By3ZWEzJDagNfAAcBdQDFgGdSrXJBwqAPwCDyzumawxdRLJEOk5U5tIYek9gubuvcPedwDRgUKkPhVXuvhjYk5ZPGRGRKlLe0E3UY5TXi4/S5mBFqeXSGvgobrsYOPFAXszMrgCuAGiX1u8ZIiKZVV4dm6htDkaUHrol2HdANXfdfZK7F7p7YcuWLQ/kECIikkSUhF4MtI3bbgOsqZxwRETkQEVJ6POAY8ysg5nVA4YAMys3LBERqahyE7q77wKuA14ClgLT3b3IzO4xs4EAZvZtMysGfgBMNLOiygxaRETKirTAhbvPAmaV2ndn3P15hKEYERHJkIytKWpm64AEa5eQB6yv4nAOlmKuGrkWc67FC4q5qhxMzO3dPeGskowl9GTMbL4nWQA1WynmqpFrMedavKCYq0plxaxaLiIi1YQSuohINZGNCX1SpgM4AIq5auRazLkWLyjmqlIpMWfdGLqIiByYbOyhi4jIAVBCFxGpJrIqoZe3kEY2MrNVZvYvM1toZvMzHU8iZvZ7M/vMzN6N29fczP5uZu/Hfh6WyRjjJYl3tJl9HHufF5rZWZmMsTQza2tms81sqZkVmdmPY/uz+X1OFnNWvtdm1sDM3jKzRbF4747t72Bmb8be46diJUqyQoqYHzOzlXHvcbe0vGCyQulVfSPCQhrZeANWAXmZjqOcGHsDPYB34/aNBUbG7o8E7st0nOXEOxq4JdOxpYi5FdAjdr8p8B7QKcvf52QxZ+V7Taj82iR2vy7wJnASMB0YEtv/W+DqTMcaIebHiLgYUEVu2dRDL3chDTkw7j4H+LzU7kHA47H7jwPnVmlQKSSJN6u5+yfu/nbs/hZC3aPWZPf7nCzmrOTB1thm3djNgdOAZ2L7s+09ThZzpcimhJ5oIY2s/ccVx4G/mdmC2AIeueJwd/8Ewn9s4BsZjieK68xscWxIJmuGLkozs3ygO6E3lhPvc6mYIUvfazOrbWYLgc+AvxO+1W/0UEQQsjBvlI7Z3Uve4zGx9/gBM6ufjtfKpoSetoU0qlgvd+8B9AeuNbPemQ6omnoY+CbQDfgE+O/MhpOYmTUBngVudPfNmY4nigQxZ+177e673b0boRhgT6BjomZVG1VqpWM2sy7Az4DjgG8DzYHb0vFa2ZTQc3IhDXdfE/v5GTCD8I8sF6w1s1YAsZ+fZTielNx9bew/xh7gEbLwfTazuoTEONXd/xTbndXvc6KYc+G9dveNwKuE8ehmZlZSOTZr80ZczP1iw13u7l8Bk0nTe5xNCT3nFtIws8Zm1rTkPvBd4N3Uz8oaM4FLYvcvAZ7PYCzlKkmKMeeRZe+zmRnwO2Cpu4+Leyhr3+dkMWfre21mLc2sWex+Q+AMwrj/bGBwrFm2vceJYv533Ie8Ecb80/IeZ9WVorHpUeMJM15+7+5jMhxSSmZ2FKFXDqG2/BPZGLOZPQmcSijZuRa4C3iOMDugHfAh8AN3z4oTkUniPZUwBOCEmUVXloxNZwMzOxl4DfgXsCe2+3bCmHS2vs/JYh5KFr7XZlZAOOlZm9AZne7u98T+H04jDF28A1wc6/lmXIqYXwFaEoaaFwJXxZ08PfDXy6aELiIiBy6bhlxEROQgKKGLiFQTSugiItWEErqISDWhhC4iUk0ooYuIVBNK6CIi1cT/B0SEbrq86vu7AAAAAElFTkSuQmCC\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "draw_graph(result, True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 91,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-03-18T04:00:47.018562Z",
     "start_time": "2020-03-18T04:00:46.905656Z"
    }
   },
   "outputs": [],
   "source": [
    "torch.save(model, \"./model_fine_tuned.pth\")"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.9"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": true,
   "toc_window_display": false
  },
  "varInspector": {
   "cols": {
    "lenName": 16,
    "lenType": 16,
    "lenVar": 40
   },
   "kernels_config": {
    "python": {
     "delete_cmd_postfix": "",
     "delete_cmd_prefix": "del ",
     "library": "var_list.py",
     "varRefreshCmd": "print(var_dic_list())"
    },
    "r": {
     "delete_cmd_postfix": ") ",
     "delete_cmd_prefix": "rm(",
     "library": "var_list.r",
     "varRefreshCmd": "cat(var_dic_list()) "
    }
   },
   "types_to_exclude": [
    "module",
    "function",
    "builtin_function_or_method",
    "instance",
    "_Feature"
   ],
   "window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
